package com.levi.juc.singlemodel;

/**
 * 懒汉式  用的时候再加载
 * 懒汉式的问题：
 * 多线程并发情况下会出现问题
 *
 * 双重检测锁模式 :先判断，再加锁，在判断，在家volitile，禁止指令重排
 */
public class LazyModel {
    private LazyModel(){
        System.out.println(Thread.currentThread().getName());
    }


    private static volatile LazyModel lazyModel;

    public static  LazyModel getInstance() {
        //1.先判断对象有没有，没有的话再加载，避免浪费内存
        //2.多线程情况下不安全，要加锁


        //双重检测锁模式，简称DCL懒汉式
        if (lazyModel == null) {
            //加锁,锁这个类，保证对象只有一个，保证线程安全问题,同一时间只有一条线程进来
            synchronized (LazyModel.class) {
                if (lazyModel == null){
                    lazyModel = new LazyModel();//new 不是一个原子性操作，极端情况下可能会出现问题
                    /**
                     * new 的执行过程:
                     * 1.分配内存空间
                     * 2.执行构造方法，初始化对象
                     * 3.把对象指向这个内存空间
                     *
                     * 指令重拍这三个顺序可能会被打乱，导致 1 3 2，这样就会还没有初始化对象的时候就把内存给占用了，然后再初始化对象
                     * 如果还没有初始化对象的时候，另外一条线程进来，那么第一个if判断就不==null，就会直接return，返回的空间没有对象
                     * 所以要加volatile，禁止指令重排
                     */
                }
            }
        }
        return lazyModel;
    }


    public static LazyModel getInstance1(){
        if (lazyModel == null) {
            synchronized (LazyModel.class){
                if (lazyModel == null) {
                    lazyModel = new LazyModel();
                }
            }
        }else {
            return lazyModel;
        }

        return lazyModel;
    }


    public static void main(String[] args) {
        for (int i = 1; i <= 20; i++) {
            new Thread(LazyModel::getInstance).start();
        }
    }

}
